/// <reference path="Scripts/knockout.d.ts" />
/// <reference path="Scripts/knockout.mapping.d.ts" />
/// <reference path="../Math/Matrix.ts" />
/// <reference path="../Math/MathHelper.ts" />
/// <reference path="../Math/Vector2.ts" />

(function (window:any) {
    var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame ||
                                window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
    window.requestAnimationFrame = requestAnimationFrame;
})(window);

var equalities = (function () {

    var translateToOrigin = new ew.Matrix(
        1, 0, 0.5, 0,
        0, 1, 0.5, 0,
        0, 0, 0, 0,
        0, 0, 0, 0
        );

    var drawOrigin = function (context) {
        var origin = { x: 0.5, y: 0.5 };
        var offset = 0.5;
        context.save();
        context.setLineDash([0]);
        context.strokeStyle = "black";
        context.beginPath();
        context.moveTo(origin.x, origin.y);
        context.lineTo(origin.x + offset, origin.y);
        context.moveTo(origin.x, origin.y);
        context.lineTo(origin.x - offset, origin.y);
        context.moveTo(origin.x, origin.y);
        context.lineTo(origin.x, origin.y + offset);
        context.moveTo(origin.x, origin.y);
        context.lineTo(origin.x, origin.y - offset);
        context.closePath();
        context.stroke();
        context.restore();
    }

    var drawPoints = function (context, points) {
        context.fillStyle = "rgba(0, 0, 0, 0.7)";
        for (var i = 0; i < points.length; i++) {
            var point = translateToOrigin.transform(points[i]);
            context.fillRect(point.x, point.y, viewModel.pointSize(), viewModel.pointSize());
        }
    }

    var drawEquality = function drawLineSimmetry(context, points, pointSize, color, epsilon, angle, a, b, shouldDrawLine) {
        var scaling = 1;
        var matrix = new ew.Matrix(
                Math.cos(angle), -epsilon * Math.sin(angle), a, 0,
                Math.sin(angle), epsilon * Math.cos(angle), b, 0,
                0, 0, 0, 0,
                0, 0, 0, 0
            ).multiply(scaling);
        var matrix = matrix;//translateToOrigin.multiply(matrix);//matrix.multiply(translateToOrigin);

        context.save();
        context.fillStyle = color;
        context.strokeStyle = color;
        for (var i = 0; i < points.length; i++) {
            var transformed = matrix.transform(points[i]);
            transformed = translateToOrigin.transform(transformed);
            var point = translateToOrigin.transform(points[i]);
            context.fillRect(transformed.x, transformed.y, pointSize, pointSize);

            context.beginPath();
            context.moveTo(point.x + pointSize / 2, point.y + pointSize / 2);
            context.lineTo(transformed.x + pointSize / 2, transformed.y + pointSize / 2);
            context.closePath();
            context.stroke();
        }
        if (shouldDrawLine) {
            context.beginPath();
            context.moveTo(0, Math.tan(angle / 2) * (-0.5) + 0.5);
            context.lineTo(1, Math.tan(angle / 2) * 0.5 + 0.5);
            context.closePath();
            context.stroke();
        }
        context.restore();
    }

    return {
        equality: drawEquality,
        origin: drawOrigin,
        points: drawPoints,
    };
})();

var model = {
    pointsCount: 5,
    pointSize: 0.02,
    lineSimmetryAngle: Math.PI / 4,
    rotationAngle: Math.PI / 6,
    translationX: 0.1,
    translationY: 0.1,
    movingReflectionAngle: Math.PI / 12,
    movingReflectionX: 0.15,
    movingReflectionY: 0.15,

    showLineSimmetry: true,
    showRotation: true,
    showTranslation: true,
    showMovingReflection: true,

}

var viewModel = ko.mapping.fromJS(model);

var points;
window.onload = function () {

    var canvas = <HTMLCanvasElement> document.getElementById("canvas-id");
    var context = canvas.getContext("2d");
    context.scale(canvas.width, canvas.height);
    context.lineWidth = 1 / canvas.width;

    var max = 1;
    var generatePoints = function generatePoints(count) : any[] {
        var points = [];
        for (var i = 0; i < count; i++) {
            var point = new ew.Vector2(Math.random() * max - max / 2, Math.random() * max - max / 2);
            points.push(point);
        }

        return points;
    };

    points = generatePoints(viewModel.pointsCount);

    var draw = function draw() {
        context.clearRect(0, 0, 1, 1);

        equalities.origin(context);

        if (points.length != viewModel.pointsCount()) {
            points = generatePoints(viewModel.pointsCount());
        }
        
        equalities.points(context, points);

        (<any>context).setLineDash([5 / canvas.width]);
        if (viewModel.showLineSimmetry()) {
            // Line simmetry
            equalities.equality(context, points, viewModel.pointSize(), "rgba(0, 0, 255, 0.7)", -1, viewModel.lineSimmetryAngle(), 0, 0, true);
        }

        if (viewModel.showRotation()) {
            // Rotation
            equalities.equality(context, points, viewModel.pointSize(), "rgba(255, 0, 0, 0.7)", 1,
                viewModel.rotationAngle(), 0, 0, false);
        }
        if (viewModel.showTranslation()) {
            // Translation
            equalities.equality(context, points, viewModel.pointSize(), "rgba(0, 255, 0, 0.7)", 1, 0,
                viewModel.translationX(), viewModel.translationY(), false);
        }
        if (viewModel.showMovingReflection()) {
            // Moving reflection
            equalities.equality(context, points, viewModel.pointSize(), "rgba(102, 102, 0, 0.7)", -1,
                viewModel.movingReflectionAngle(), viewModel.movingReflectionX(), viewModel.movingReflectionY(), true);
        }


        requestAnimationFrame(draw);
    }
    ko.applyBindings(viewModel);

    draw();
};